package de.bazinga.rotw.game;


import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Properties;
import java.util.Vector;
import java.util.concurrent.Callable;

import com.jme.input.InputHandler;
import com.jme.math.Plane;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.renderer.pass.BasicPassManager;
import com.jme.scene.Node;
import com.jme.scene.Skybox;
import com.jme.scene.Spatial;
import com.jme.scene.state.RenderState;
import com.jme.system.DisplaySystem;
import com.jme.util.GameTaskQueueManager;
import com.jme.util.Timer;
import com.jmex.effects.glsl.BloomRenderPass;
import com.jmex.effects.water.ProjectedGrid;
import com.jmex.effects.water.WaterHeightGenerator;
import com.jmex.effects.water.WaterRenderPass;
import com.jmex.game.state.BasicGameState;
import com.jmex.game.state.GameState;
import com.jmex.jbullet.PhysicsSpace;
import com.jmex.jbullet.nodes.PhysicsCharacterNode;
import com.jmex.jbullet.nodes.PhysicsNode;
import com.jmex.terrain.TerrainBlock;

import de.bazinga.rotw.collision.CollidableObjects;
import de.bazinga.rotw.collision.GameCollisionListener;
import de.bazinga.rotw.effects.BulletHoles;
import de.bazinga.rotw.effects.Nightvision;
import de.bazinga.rotw.effects.ParticleEffects;
import de.bazinga.rotw.gameModes.GameMode;
import de.bazinga.rotw.hud.GameHUD;
import de.bazinga.rotw.input.GameInputHandler;
import de.bazinga.rotw.map.MapList;
import de.bazinga.rotw.map.MapLoader;
import de.bazinga.rotw.network.BasicSyncManager;
import de.bazinga.rotw.network.Client;
import de.bazinga.rotw.network.Server;
import de.bazinga.rotw.network.ServerList;
import de.bazinga.rotw.network.message.physics.ObjectLocationMessage;
import de.bazinga.rotw.objects.GameObject;
import de.bazinga.rotw.person.OpponentList;
import de.bazinga.rotw.person.Person;
import de.bazinga.rotw.player.Player;
import de.bazinga.rotw.sound.Sound;
import de.bazinga.rotw.statistics.OnlineStatistics;
import de.bazinga.rotw.texture.TextureCache;
import de.bazinga.rotw.util.GlobalSettings;
import de.bazinga.rotw.weapon.Knife;
import de.bazinga.rotw.weapon.Pistol;
import de.bazinga.rotw.weapon.Rifle;
import de.bazinga.rotw.weapon.Uzi;
import de.bazinga.rotw.weapon.grenade.GrenadeList;
import de.bazinga.rotw.weapon.pistol.bullet.BulletList;
import de.bazinga.rotw.weapon.portal.PortalGun;
import de.bazinga.rotw.weapon.portal.PortalList;

public class RotwGameState extends BasicGameState {
	
	
	/**
	 * Physics
	 */
	private PhysicsSpace pSpace = PhysicsSpace.getPhysicsSpace(PhysicsSpace.BroadphaseTypes.AXIS_SWEEP_3);

    public static PhysicsCharacterNode character;
    public static Vector3f walkDirection=new Vector3f();
	
	
	public PhysicsNode boxNode = null;
	
	/**
	 * The PassManager
	 */
	protected BasicPassManager pManager;
	private BloomRenderPass bloomRenderPass;
	//private static ShadowedRenderPass sPass = new ShadowedRenderPass();

    private WaterRenderPass waterEffectRenderPass;
    private ProjectedGrid projectedGrid;
    private WaterHeightGenerator waterHeightGenerator;
	
	
    /**
     * High resolution timer for jME.
     */
    protected Timer timer;
	protected InputHandler gameInput = null;
	
	private GameHUD hud;
	private Node weaponNode = new Node("Weapon");
	
	
	private Player player = null;
	


	private boolean isRunning = false;
	
	
	private Vector<Spatial> objectsToRemove = new Vector<Spatial>();
	
	private BasicSyncManager syncManager = null;
	
	
	
	private String serverName = "Unnamed";
	private long lastUpdateSend = 0;
	
	
	
	private Properties props = new Properties();
	
	
	/**
	 * Current Map-Stuff
	 */
	private String currentMapName = "";
	private int currentMapIndex = 0;
	private GameMode gameMode = null;
	private boolean useTeams = true;
	
	
	/**
	 * If this is >0, the client will change the map on the next update
	 */
	private int mapChangeIndex = -1;

	
	
	/**
	 * Team Scores
	 */
	public static int teamOneScore = 0;
	public static int teamTwoScore = 0;
	
	/**
	 * Items to be Respawned
	 */
	private Vector<GameObject> respawnItems = new Vector<GameObject>();
	
	
	/**
	 * The Skybox
	 */
	private Skybox skybox = null;
	
	/**
	 * The Terrain
	 */
	private TerrainBlock terrainBlock = null;
	private PhysicsNode terrainPhysicsNode = null;
	
	/**
	 * The time when the messages were added so they dont stay longer than x seconds
	 */
	private long[] chatMsgTime = new long[4];
	
	/**
	 * The Default-Weapons for the players
	 */
	private String[] defaultWeapons = {"Knife","Pistol","Portal"};
	
	
	public RotwGameState() {
		super("gameState");
		
		// Init the PassManager
		pManager = new BasicPassManager();
		
		bloomRenderPass = new BloomRenderPass(Game.getGame().getCamera(), 6);
		bloomRenderPass.setExposurePow(6f);
		bloomRenderPass.setBlurIntensityMultiplier(0.6f);
		
		if(!bloomRenderPass.isSupported()) {
	    	System.err.println("Bloom not Supported");
	    	System.exit(0);
	    } else {
	        bloomRenderPass.add(rootNode);
	        bloomRenderPass.setUseCurrentScene(false);
	        pManager.add(bloomRenderPass);
	    }
		
		
		
		/**
		 * Init Water!
		 */
		boolean waterEnabled = true;
		float waterHeight = -5.0f;
		float waveMaxHeight = 1.5f;
		float waveMinHeight = 0.3f;
		
		waterEffectRenderPass = new WaterRenderPass(Game.getGame().getCamera(), 4, true, true);
        waterEffectRenderPass.setClipBias(0.5f);
        waterEffectRenderPass.setWaterMaxAmplitude(0f);
        waterEffectRenderPass.setFallbackTexture(TextureCache.getInstance().getTexture("water.png").getTexture());
        // setting to default value just to show
        waterEffectRenderPass.setWaterPlane(new Plane(new Vector3f(0.0f, waterHeight,
                0.0f), 0.0f));
        waterEffectRenderPass.setEnabled(waterEnabled);
        
        waterHeightGenerator = new WaterHeightGenerator();
        waterHeightGenerator.setHeightbig(waveMaxHeight);
        waterHeightGenerator.setHeightsmall(waveMinHeight);
        projectedGrid = new ProjectedGrid("ProjectedGrid", Game.getGame().getCamera(), 100, 70, 0.01f,
        		waterHeightGenerator);
        projectedGrid.getLocalTranslation().setY(waterHeight);
        waterEffectRenderPass.setWaterEffectOnSpatial(projectedGrid);
        rootNode.attachChild(projectedGrid);
        pManager.add(waterEffectRenderPass);

		
        
        
        
		// Load Properties
		props.setProperty("playerName", "Anonymous");
		props.setProperty("gameCode", "");
		
		// Try to load props
		try {
			FileInputStream in = new FileInputStream("gameProps");
			props.load(in);
			in.close();
		} catch (FileNotFoundException e) {
			System.out.println("couldnt load properties");
		} catch (IOException e) {
			System.out.println("couldnt load properties");
		}
		
		
		timer = Timer.getTimer();
		
		OnlineStatistics.updateTimeStarted = System.currentTimeMillis();
		
		//Game.getGame().getDisplay().getRenderer().setBackgroundColor(ColorRGBA.blue);
		
		//Model.createJmeFrom3DS(RotwGameState.class.getClassLoader().getResource("portal.3ds"), "bin/portal.jme");
		
		// Set Default-Weapons
		
		
		/**
		 * TODO
		 * 
		 *  
		 *  - Trefferquote
		 *  
		 *  - PRESENT ZOOM, BULLETHOLES
		 * 
		 * - CHEAT
		 * 
		 */
		
		// Preload Sound
		File soundDir = new File("sounds/");
		File[] sounds = soundDir.listFiles();
		for(File s:sounds) {
			if(s.getName().endsWith(".wav")) {
				Sound.getInstance().addSound("sounds/"+s.getName());
			}
		}
		
		
		
		
		/**
		 * Player
		 */
		player = new Player();
		getRootNode().attachChild(player.getPhysicsNode());
        
		// Init Stuff
		initInput();
		
		/**
		 * Text
		 */
		TextCache.getInstance().addText("armor", new TextField("Armor: "+player.getArmor(), ColorRGBA.darkGray,new Vector3f(15,15,5),1f));
		TextCache.getInstance().addText("health", new TextField("Health: "+player.getHealth(), ColorRGBA.darkGray,new Vector3f(15,45,5),1f));
		TextCache.getInstance().addText("ammo", new TextField("Ammunition: "+player.getAmmo(), ColorRGBA.darkGray,new Vector3f(15,70,5),1f));
		TextCache.getInstance().addText("magazine", new TextField("Magazines: "+player.getCurrentWeapon().getMagazines(), ColorRGBA.darkGray,new Vector3f(15,95,5),1f));

		TextCache.getInstance().addText("fps", new TextField("FPS: "+timer.getFrameRate(), ColorRGBA.white,new Vector3f(5,Game.getGame().getDisplay().getHeight()-15,5),1f));
		TextCache.getInstance().addText("score", new TextField("Score: "+player.getScore(), ColorRGBA.white,new Vector3f(5,Game.getGame().getDisplay().getHeight()-25,5),1f));
		

		TextCache.getInstance().addText("chat1", new TextField("Chat", ColorRGBA.white,new Vector3f(5,Game.getGame().getDisplay().getHeight()-50,5),1f));
		TextCache.getInstance().addText("chat2", new TextField("", ColorRGBA.white,new Vector3f(5,Game.getGame().getDisplay().getHeight()-65,5),1f));
		TextCache.getInstance().addText("chat3", new TextField("", ColorRGBA.white,new Vector3f(5,Game.getGame().getDisplay().getHeight()-80,5),1f));
		TextCache.getInstance().addText("chat4", new TextField("", ColorRGBA.white,new Vector3f(5,Game.getGame().getDisplay().getHeight()-95,5),1f));
		TextCache.getInstance().addText("chatMsg", new TextField("", ColorRGBA.white,new Vector3f(5,Game.getGame().getDisplay().getHeight()-110,5),1f));
		
		
		
		/**
		 * HUD
		 */
		hud = new GameHUD();
		updateWeaponIcon();
		
		Nightvision.getInstance().init(getRootNode());
		
		
		
		
		/**
		 * Preload Weapons
		 */
		Knife.initWeaponModel();
		Pistol.initWeaponModel();
		Rifle.initWeaponModel();
		Uzi.initWeaponModel();
		PortalGun.initWeaponModel();
	}
	
	
	
	
	/**
	 * initializes the GameState
	 */
	private void initInput() {
		gameInput = new GameInputHandler(player,0.5f);
	}

    

	/**
	 * Locks the Objects, Walls and Stairs-Node
	 */
	public void lockNodes() {
		GameTaskQueueManager.getManager().update(new Callable<Object>() {
			public Object call() throws Exception {
				CollidableObjects.getInstance().getObjects("wallNode").get(0).lock();
				CollidableObjects.getInstance().getObjects("wallNode").get(0).lockBranch();
				CollidableObjects.getInstance().getObjects("groundNode").get(0).lock();
				CollidableObjects.getInstance().getObjects("groundNode").get(0).lockBranch();
				
				// Lock objects?
				Vector<Spatial> obj = CollidableObjects.getInstance().getObjects("object");
				if(obj != null) {
					for(Spatial wall:obj) {
						wall.lock();
					}
				}
				
				// Lock items?
				obj = CollidableObjects.getInstance().getObjects("health");
				if(obj != null) {
					for(Spatial wall:obj) {
						wall.lock();
					}
				}
				obj = CollidableObjects.getInstance().getObjects("armor");
				if(obj != null) {
					for(Spatial wall:obj) {
						wall.lock();
					}
				}
				obj = CollidableObjects.getInstance().getObjects("ammo");
				if(obj != null) {
					for(Spatial wall:obj) {
						wall.lock();
					}
				}
				
				
				return null;
			}
        });
	}
	
	
	/**
	 * Set the bullet-color of the player
	 * @param color the bullet color of the player
	 */
	public void setPlayerBulletColor(ColorRGBA color) {
		if(player != null) {
			player.setBulletColor(color);
		}
	}
	
	
	
	
	/**
	 * Reset Game
	 * You need to reset the PhysicsSpace with {@link #recreatePhysicsSpace()} before reseting the game!
	 * This should be done in the same thread like the update-method
	 * @param mapIndex the index of the map
	 */
	public void reset(int mapIndex, boolean resetOpponents) {	
		this.currentMapName = MapList.getInstance().getMapList().get(mapIndex).get("name");
		this.mapChangeIndex = -1;
		
		setCurrentMapIndex(mapIndex);

		getRootNode().detachAllChildren();
		getRootNode().attachChild(player.getPhysicsNode());
		
		PhysicsSpace.getPhysicsSpace().add(player.getPhysicsNode());
		
		if(!resetOpponents) {
			Enumeration<Person> e = OpponentList.getInstance().getOpponents().elements();
			while(e.hasMoreElements()) {
				Person p = e.nextElement();
				p.resetServer(true);
				getRootNode().attachChild(p.getBodyPhysicsNode());
			}
		}
		
		getRootNode().attachChild(hud);
		getRootNode().clearRenderState(RenderState.StateType.Fog);
		
		// Add Particles to the rootNode
		ParticleEffects.getInstance().addToNode(getRootNode());
		
		
		// Remove everything
		PortalList.getInstance().clear();
		BulletList.getInstance().removeAll();
		if(resetOpponents) OpponentList.getInstance().removeAll();
		
		BulletList.getInstance().clearUnusedBullets();
		GrenadeList.getInstance().clearUnusedGrenade();
		
		
		// Add Player again
		if(resetOpponents) {
			OpponentList.getInstance().addOpponent(-1, player);
		}
		
		
		
		CollidableObjects.getInstance().clear();
		
		

		
		/**
		 * Init BulletHoles
		 */
		BulletHoles.getInstance().init(getRootNode());
		

		
		
		try{
			MapLoader.loadMap(getRootNode(),MapList.getInstance().getMapList().get(mapIndex).get("path"),player);
		}catch(Exception e) {
			e.printStackTrace();
			
			return ;
		}
		
		lockNodes();
		
		

		waterEffectRenderPass.clearReflectedScene();
		if(terrainBlock != null) waterEffectRenderPass.setReflectedScene(terrainBlock);
		waterEffectRenderPass.setSkybox(skybox);
		getRootNode().attachChild(projectedGrid);
		
		
		// Reset Collision-Vector
		player.reset();

		if(player.getWeapon(PortalGun.class) != null) {
			PortalList.getInstance().addPortal(
					((PortalGun)player.getWeapon(PortalGun.class)).getEntry());
			// Add Player-Portals again
			((PortalGun)player.getWeapon(PortalGun.class)).addPortals(getRootNode());
		}		
		
		
		// Add Weapon-Model
		if(player.getCurrentWeapon().getWeaponModel() != null)
			weaponNode.attachChild(player.getCurrentWeapon().getWeaponModel());
		getRootNode().attachChild(weaponNode);
		
        
		System.out.println(getGameMode());		
		// Reset the GameMode
		gameMode.reset();
		
        
		
		// Finish up
		getRootNode().updateRenderState();
		getRootNode().updateWorldBound();
		getRootNode().updateGeometricState(0.0f, true);
		
		// Add CollisionListener
		pSpace.addCollisionListener(new GameCollisionListener());
		System.out.println("CollitionListener Added");
		
		
		isRunning = true;
	}
	
	public void reset(int mapIndex) {
		reset(mapIndex,true);
	}
	
	public void reset() {
		reset(currentMapIndex,true);
	}
	
	
	public void recreatePhysicsSpace() {
		PhysicsSpace.getPhysicsSpace().destroy();
		pSpace = PhysicsSpace.getPhysicsSpace(PhysicsSpace.BroadphaseTypes.AXIS_SWEEP_3);
	}
	
	
	
	
	
	public void resetWaterEffects(float waterHeight, float waveMaxHeight, float waveMinHeight) {
		waterEffectRenderPass.getWaterPlane().getNormal().setY(waterHeight);
		projectedGrid.getLocalTranslation().setY(waterHeight);
		waterHeightGenerator.setHeightbig(waveMaxHeight);
		waterHeightGenerator.setHeightsmall(waveMinHeight);
		
		waterEffectRenderPass.setEnabled(true);
	}
	
	public void resetWaterEffects() {
		resetWaterEffects(-99999f, 0, 0);
		waterEffectRenderPass.setEnabled(false);
	}
	
	
	public float getWaterHeight() {
		return projectedGrid.getLocalTranslation().getY();
	}
	
	
	public float getWaterHeight(Vector3f location) {
		return waterHeightGenerator.getHeight(
				location.getX(), 
				location.getZ(), 
				Timer.getTimer().getTimeInSeconds()) + projectedGrid.getLocalTranslation().getY();
	}
	

	/**
	 * Updates the rootNode.
	 * 
	 * @see GameState#update(float)
	 */
	public void update(float tpf) {
		super.update(tpf);
		
		pManager.updatePasses(tpf);

		// Update physics
		PhysicsSpace.getPhysicsSpace().update(tpf);
		
		// Check for Respawning GameObject
		Enumeration<GameObject> e = respawnItems.elements();
		while(e.hasMoreElements()) {
			GameObject o = e.nextElement();
			if(o.respawn()) {
				respawnItems.remove(o);
			}
		}
		
		// Remove Spatials
		for(Spatial b:objectsToRemove) {
			rootNode.detachChild(b);
		}
		objectsToRemove.clear();
		
		// The Player-Body should look in the direction of the Camera
		if(!player.isDead()) {
			Vector3f camDir = Game.getGame().getCamera().getDirection().clone();
			Vector3f camPos = Game.getGame().getCamera().getLocation().clone();
			camPos.setY(player.getLocalTranslation().getY());
			camDir.setY(0);
			player.lookAt(camPos.add(camDir.mult(5)), Vector3f.UNIT_Y);

	        weaponNode.setLocalTranslation(Game.getGame().getCamera().getLocation());
			weaponNode.lookAt(weaponNode.getLocalTranslation().add(Game.getGame().getCamera().getDirection()), Vector3f.UNIT_Y);
		}
		//input.update(tpf);
		gameInput.update(tpf);
		
		
		gameMode.gameUpdate();
		
		// Check if Physics-Object collides with Portal
		collisionPhysicsWithPortal();
		
		// Update the Chat-Messages (e.g. delete old ones)
		updateChatMessages();

		
		// Update FPS
		TextCache.getInstance().getTextfield("fps").setText("FPS: "+timer.getFrameRate());
		
		
		// Update Radar
		hud.updateRadar();
		
		
		/**
		 * Reset?
		 */
		if(this.mapChangeIndex >= 0) {
			recreatePhysicsSpace();
			reset(mapChangeIndex, false);
		}
		
		// Send Server-Information
		if(isServer() && (System.currentTimeMillis() - lastUpdateSend) > 60000*5) {
			ServerList.sendServerUpdate(getServerName());
			lastUpdateSend = System.currentTimeMillis();
		}
		
		
	}

	/**
	 * Draws the rootNode.
	 * 
	 * @see GameState#render(float)
	 */
	public void render(float tpf) {		
		//Debugger.drawBounds( rootNode, Game.getGame().getDisplay().getRenderer(), true );
		//PhysicsDebugger.drawWireframes( DisplaySystem.getDisplaySystem().getRenderer() );
		
		super.render(tpf);
		
		/** Have the PassManager render. */
        pManager.renderPasses(Game.getGame().getDisplay().getRenderer());
		
		/**
		 * Draw Text
		 */
		Enumeration<String> e = TextCache.getInstance().getKeys();
		while(e.hasMoreElements()) {
			DisplaySystem.getDisplaySystem().getRenderer().draw(
					TextCache.getInstance().getTextfield(
							e.nextElement()));
		}
	}
	
	
	
	
	public void collisionPhysicsWithPortal() {
		/**
		 * Collision with Portal?
		 */
		PortalGun pg = (PortalGun)player.getWeapon(PortalGun.class);
		if(pg != null && pg.getEntry() != null && pg.getExit() != null) {
			Vector<Spatial> obj = CollidableObjects.getInstance().getObjects("physics");
			if(obj != null) {
				for(int i=0;i<obj.size();i++) {
					if(obj.get(i).hasCollision(pg.getEntry(), false)) {
						Vector3f newLoc = pg.getExit().getDestLocation();
						obj.get(i).setLocalTranslation(
								newLoc.x, 
								newLoc.y, 
								newLoc.z);
						
						// Send Message
						ObjectLocationMessage olm = new ObjectLocationMessage();
						olm.setNewLocation(newLoc);
						olm.setPhysicsIndex(i);
						if(syncManager instanceof Server) {
							((Server)syncManager).getServer().sendToAll(olm);
						}else{
							((Client)syncManager).getClient().sendToServer(olm);
						}
					}
				}
			}
		}
	}
	
	
	
	/**
	 * Add a new Chatmessage to the Output
	 * @param msg the Chatmessage
	 */
	public void addChatMessage(String msg) {
		if(msg.endsWith("ring") && Game.getGame().getSettings().isSFX()) {
			Sound.getInstance().getAudioTrack("sounds/ring.wav").play();
		}
		
		if(TextCache.getInstance().getTextfield("chat1").getText().equals("")) {
			TextCache.getInstance().getTextfield("chat1").setText(msg);
			chatMsgTime[0] = System.currentTimeMillis();
		}else if(TextCache.getInstance().getTextfield("chat2").getText().equals("")) {
		 TextCache.getInstance().getTextfield("chat2").setText(msg);
			chatMsgTime[1] = System.currentTimeMillis();
		}else if(TextCache.getInstance().getTextfield("chat3").getText().equals("")) {
		 TextCache.getInstance().getTextfield("chat3").setText(msg);
			chatMsgTime[2] = System.currentTimeMillis();
		}else if(TextCache.getInstance().getTextfield("chat4").getText().equals("")) {
		 TextCache.getInstance().getTextfield("chat4").setText(msg);
			chatMsgTime[3] = System.currentTimeMillis();
		}else{
			// All full, so set it to 4 and move the others up
			for(int i = 0; i <= 2; i++) {
				TextCache.getInstance().getTextfield("chat"+(i+1)).setText(
						TextCache.getInstance().getTextfield("chat"+(i+2)).getText());
				chatMsgTime[i] = chatMsgTime[i+1];
			}
			
			TextCache.getInstance().getTextfield("chat4").setText(msg);
			chatMsgTime[3] = System.currentTimeMillis();
		}
	}
	
	/**
	 * Removes the old ChatMessages
	 */
	private void updateChatMessages() {
		if((System.currentTimeMillis() - chatMsgTime[0]) > GlobalSettings.SHOWCHATMSGDURATION) {
			// Delete first one and move others up
			for(int i = 0; i <= 2; i++) {
				TextCache.getInstance().getTextfield("chat"+(i+1)).setText(
						TextCache.getInstance().getTextfield("chat"+(i+2)).getText());
				chatMsgTime[i] = chatMsgTime[i+1];
			}
			
			
			TextCache.getInstance().getTextfield("chat4").setText("");
			chatMsgTime[3] = 0;
		}
	}
	
	
	
	/**
	 * Updates the Weapon-Icon on the HUD
	 */
	public void updateWeaponIcon() {
		if(player.getCurrentWeapon() != null) {
			hud.setWeaponIcon(player.getCurrentWeapon().getIcon());
			
			weaponNode.detachAllChildren();
			if(player.getCurrentWeapon().getWeaponModel() != null)
				weaponNode.attachChild(player.getCurrentWeapon().getWeaponModel());
		}
	}


	
	public void addItemToRespawn(GameObject o) {
		respawnItems.add(o);
	}
	
	
	/**
	 * Disconnect the the Server/client
	 */
	public void disconnect() {
		if(syncManager == null) return ;
		if(syncManager instanceof Server) {
			((Server)syncManager).close();
		}else if(syncManager instanceof Client) {
			((Client)syncManager).close();
		}
	}

	
	/**
	 * Is this a Server or a Client
	 * @return true if it's a server
	 */
	public boolean isServer() {
		return (syncManager instanceof Server);
	}
	
	
	
	
	/**
	 * Is the Game running? For the continue button
	 * @return true if a game is running
	 */
	public boolean isRunning() {
		return isRunning;
	}
	
	
	/**
	 * Set if the Game is running
	 * @param running
	 */
	public void setRunning(boolean running) {
		this.isRunning = running;
	}
	
	
	/**
	 * Returns the player
	 * @return the player
	 */
	public Player getPlayer() {
		return player;
	}

	
	
	public GameHUD getHUD() {
		return hud;
	}
	
	
	public void addSpatialToRemove(Spatial b) {
		objectsToRemove.add(b);
	}
	
	
	public BasicSyncManager getSyncManager() {
		return syncManager;
	}


	public void setSyncManager(BasicSyncManager syncManager) {
		this.syncManager = syncManager;
	}
	
	
	public String getCurrentMapName() {
		return currentMapName;
	}




	public Properties getProps() {
		return props;
	}




	public void setProps(Properties props) {
		this.props = props;
	}
	




	public TerrainBlock getTerrainBlock() {
		return terrainBlock;
	}




	public void setTerrainBlock(TerrainBlock terrainBlock) {
		this.terrainBlock = terrainBlock;
	}




	public void setDefaultWeapons(String[] defaultWeapons) {
		this.defaultWeapons = defaultWeapons;
		if(defaultWeapons.length == 0) {
			setDefaultWeapons(new String[]{"Knife","Pistol","Portal"});
		}
	}




	public String[] getDefaultWeapons() {
		return defaultWeapons;
	}




	public void setServerName(String serverName) {
		this.serverName = serverName;
	}




	public String getServerName() {
		return serverName;
	}




	public long getLastUpdateSend() {
		return lastUpdateSend;
	}




	public void setLastUpdateSend(long lastUpdateSend) {
		this.lastUpdateSend = lastUpdateSend;
	}




	public void setGameMode(GameMode gameMode) {
		this.gameMode = gameMode;
		
		useTeams = gameMode.useTeams();
	}




	public GameMode getGameMode() {
		return gameMode;
	}


	public boolean useTeams() {
		return useTeams;
	}




	public BloomRenderPass getBloomRenderPass() {
		return bloomRenderPass;
	}




	public void setBloomRenderPass(BloomRenderPass bloomRenderPass) {
		this.bloomRenderPass = bloomRenderPass;
	}




	public void setSkybox(Skybox skybox) {
		this.skybox = skybox;
	}




	public Skybox getSkybox() {
		return skybox;
	}




	public PhysicsSpace getPhyicsSpace() {
		return pSpace;
	}




	public void setTerrainPhysicsNode(PhysicsNode terrainPhysicsNode) {
		this.terrainPhysicsNode = terrainPhysicsNode;
	}




	public PhysicsNode getTerrainPhysicsNode() {
		return terrainPhysicsNode;
	}




	public void setCurrentMapIndex(int currentMapIndex) {
		this.currentMapIndex = currentMapIndex;
	}




	public int getCurrentMapIndex() {
		return currentMapIndex;
	}




	public void setMapChangeIndex(int mapChangeIndex) {
		this.mapChangeIndex = mapChangeIndex;
	}




	public int getMapChangeIndex() {
		return mapChangeIndex;
	}
}
